package com.vision.sales.cm.db.data;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import net.sf.gilead.pojo.gwt.LightEntity;

import com.vision.core.cm.data.IHasSystemTime;
import com.vision.core.cm.db.data.Company;
import com.vision.sales.cm.data.IHasSalesInvoice;
import com.vision.sales.cm.data.IHasTransactionStatus;
import com.vision.sales.cm.data.TransactionStatus;

/**
 * 
 * @author Mark
 *
 */
@Entity
@Table(name = AppliedAdvancePayment.TABLE)
public class AppliedAdvancePayment extends LightEntity implements Serializable, IHasSalesInvoice, IHasTransactionStatus, IHasSystemTime {

	private static final long serialVersionUID = -2027926235588250245L;
	
	public static final String TABLE = "applied_advance_payment";
	
	public static final String COL_ID = "id";
	public static final String COL_COMPANY_ID = "company_id";
	public static final String COL_CUSTOMER_ID = "customer_id";
	public static final String COL_ADVANCE_PAYMENT_ID = "advance_payment_id";
	public static final String COL_SALES_INVOICE_ID = "invoice_id";
	public static final String COL_DATE_APPLIED = "date_applied";
	public static final String COL_APPLIED_AMOUNT = "applied_amount";
	public static final String COL_STATUS = "status";
	
	public static final String COL_SYS_CREATED = "sys_created";
	public static final String COL_SYS_LAST_MOD = "sys_last_mod";
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "sapplied_advance_payment")
	@SequenceGenerator(name = "sapplied_advance_payment", sequenceName = "applied_advance_payment_seq")
	@Column(name = COL_ID)
	private Long id;
	
	/**
	 * The {@link Company} for this transaction. This must be the same as the
	 * company in {@link #advancePayment} and in {@link #salesInvoice}.
	 */
	@ManyToOne
	@JoinColumn(name = COL_COMPANY_ID, nullable = false)
	private Company company;
	
	/**
	 * The {@link Customer} for this transaction. This must be the same as the
	 * customer in {@link #advancePayment} and in {@link #salesInvoice}.
	 */
	@ManyToOne
	@JoinColumn(name = COL_CUSTOMER_ID, nullable = false)
	private Customer customer;
	
	@ManyToOne
	@JoinColumn(name = COL_ADVANCE_PAYMENT_ID, nullable = false)
	private AdvancePayment advancePayment;
	
	@ManyToOne
	@JoinColumn(name = COL_SALES_INVOICE_ID, nullable = false)
	private SalesInvoice salesInvoice;
	
	@Column(name = COL_DATE_APPLIED, nullable = false)
	@Temporal(TemporalType.DATE)
	private Date dateApplied;
	
	@Column(name = COL_APPLIED_AMOUNT, nullable = false)
	private double appliedAmount;
	
	@Column(name = COL_STATUS, nullable = false)
	@Enumerated(EnumType.STRING)
	private TransactionStatus status;
	
	@Transient
	private double balance;
	
	// For internal use %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	/**
	 * The server {@link Timestamp} this object was created.
	 */
	@Column(name = COL_SYS_CREATED, nullable = false)
	private Timestamp sysCreated;
	
	/**
	 * The server {@link Timestamp} this object was last modified.
	 */
	@Column(name = COL_SYS_LAST_MOD, nullable = false)
	private Timestamp sysLastModified;
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	public AppliedAdvancePayment() { } // For Serializable
	
	public AppliedAdvancePayment(AdvancePayment advancePayment) {
		this(advancePayment, null, 0);
	}
	
	public AppliedAdvancePayment(AdvancePayment advancePayment, SalesInvoice salesInvoice, double appliedAmount) {
		assert (advancePayment.getCompany().equals(salesInvoice.getCompany()));
		assert (advancePayment.getCustomer().equals(salesInvoice.getCustomer()));
		
		this.company = advancePayment.getCompany();
		this.customer = advancePayment.getCustomer();
		this.advancePayment = advancePayment;
		this.salesInvoice = salesInvoice;
		this.appliedAmount = appliedAmount;
	}
	
	@Override
	public boolean equals(Object object) {
		if (object instanceof AppliedAdvancePayment) {
			AppliedAdvancePayment o = (AppliedAdvancePayment) object;
			return id.equals(o.id);
		}
		return false;
	}
	
	@Override
	public int hashCode() {
		return id == null ? super.hashCode() : id.hashCode();
	}
	
	@Override
	public String toString() {
		return id + ": " + getCustomer().getCode() + ":" + getAdvancePayment().getAdvancePaymentNo() + ", " + getSalesInvoice().getInvoiceNo() + ": " + getAppliedAmount();
	}
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}
	
	public Company getCompany() {
		return company;
	}
	
	public void setCompany(Company company) {
		this.company = company;
	}
	
	public Customer getCustomer() {
		return customer;
	}

	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
	
	public AdvancePayment getAdvancePayment() {
		return advancePayment;
	}

	public void setAdvancePayment(AdvancePayment advancePayment) {
		this.advancePayment = advancePayment;
	}

	public SalesInvoice getSalesInvoice() {
		return salesInvoice;
	}

	public void setSalesInvoice(SalesInvoice salesInvoice) {
		this.salesInvoice = salesInvoice;
	}

	public Date getDateApplied() {
		return dateApplied;
	}

	public void setDateApplied(Date dateAppplied) {
		this.dateApplied = dateAppplied;
	}

	public double getAppliedAmount() {
		return appliedAmount;
	}

	public void setAppliedAmount(double appliedAmount) {
		this.appliedAmount = appliedAmount;
	}

	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}

	@Override
	public Timestamp getSysCreated() {
		return sysCreated;
	}

	@Override
	public void setSysCreated(Timestamp sysCreated) {
		this.sysCreated = sysCreated;
	}

	@Override
	public Timestamp getSysLastModified() {
		return sysLastModified;
	}

	@Override
	public void setSysLastModified(Timestamp sysLastModified) {
		this.sysLastModified = sysLastModified;
	}

	@Override
	public TransactionStatus getStatus() {
		return status;
	}
	
	public void setStatus(TransactionStatus status) {
		this.status = status;
	}
	
	public String getReferenceNo() {
		return getAdvancePayment().getAdvancePaymentNo() + "-" + getSalesInvoice().getInvoiceNo();
	}

}
